import os
import csv
import ast
import math
import numpy as np

# def is_hadamard_difference_set(difference_set):
#     n = len(difference_set)
#     # Check if the size of the difference set is a power of 2
#     if n & (n - 1) != 0 or n == 0:
#         return False

#     # Check if the difference set forms a Hadamard matrix
#     hadamard_matrix = np.zeros((n, n), dtype=int)
#     hadamard_matrix[0, :] = 1

#     for i in range(1, n):
#         for j in range(n):
#             hadamard_matrix[i, j] = difference_set[j] == difference_set[(j + i) % n]

#     return np.all(np.dot(hadamard_matrix, hadamard_matrix.T) == n)

# def is_singer_difference_set(difference_set):
#     v = len(difference_set)
#     k = sum(difference_set) // v
#     lam = difference_set.count(0)

#     if v != k * (k - 1) or lam != 1 or v % 2 == 0:
#         return False

#     for i in range(v):
#         if sum(difference_set[j] for j in range(v) if j != i and j != (i + 1) % v) != 0:
#             return False

#     return True

# 读取文件，获取所有的循环群的阶数和索引
def get_all_cyclic_groups(csv_file):
    result = []
    with open(csv_file, 'r') as file:
        reader = csv.reader(file)
        for row in reader:
            if len(row) == 3 and row[-1]==" true":
                result.append((int(row[0]), int(row[1])))
    return result

def is_hadamard(v, k, lambd):
    if (v+1) % 4 ==0 :
        n = (v+1)/4
        if (2*n - 1) == k and n-1 == lambd and is_prime_power(v):
            return True
        else:
            return False
    else:
        return False

def get_all_prime_power():
    return [2, 4, 8, 16, 32, 64, 3, 9, 27, 81, 5, 25, 7, 49, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

def get_all_singer_ds():
    powers = get_all_prime_power()
    singers = []
    for q in powers:
        for n in range(2,10):
            if((q**(n+1) - 1)/(q-1) < 100):
                singers.append((int((q**(n+1) - 1)/(q-1)), int((q**n - 1)/(q-1)), int((q**(n-1) - 1)/(q-1))))
    return singers

def is_singer(v, k, lambd):
    singers = [(7, 3, 1), (15, 7, 3), (31, 15, 7), (63, 31, 15), (21, 5, 1), (85, 21, 5), (73, 9, 1), (13, 4, 1), (40, 13, 4), (91, 10, 1), (31, 6, 1), (57, 8, 1)]
    return (v,k,lambd) in singers

def is_prime_power(num):
    """
    Checks if a number is a prime power.
    """
    if num <= 1:
        return False
    if is_prime(num):
        return True
    for i in range(2, int(math.sqrt(num)) + 1):
        if is_prime(i):
            exponent = 2
            while i**exponent <= num:
                if i**exponent == num:
                    return True
                exponent += 1
    return False

def is_prime(n):
    if n <= 1:
        return False
    elif n <= 3:
        return True
    elif n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

# 把所有单个的csv文件 合并成一个总的csv文件
def combine_csv_files(source_dir, output_file):
    # Get a list of all CSV files in the source directory
    csv_files = [file for file in os.listdir(source_dir) if (file.endswith(".csv") and "cyclic-groups.csv" != file)]

    # Sort the CSV files based on the first and second numbers in the filename
    csv_files.sort(key=lambda x: tuple(map(int, x[:-4].split("-")[:2])))

    # Create the output file
    with open(output_file, "w", newline="") as outfile:
        writer = csv.writer(outfile)

        # Flag to track if the header row has been written
        header_written = False

        # Process each CSV file
        for csv_file in csv_files:
            csv_file_path = os.path.join(source_dir, csv_file)

            with open(csv_file_path, "r") as infile:
                reader = csv.reader(infile)
                if header_written:
                    next(reader)
                # Process each row in the current CSV file
                for row in reader:
                    if not header_written:
                        header_written = True
                    writer.writerow(row)  # Write the data rows

            print(f"Processed: {csv_file_path}")


# convert ds in list to binary sequence 
def convert_to_sequence(ds, v):
    result = [-1 for _ in range(v)]
    for i in ds:
        result[i-1] = 1
    return result


def run_length_encoding(sequence):
    if not sequence:
        return []

    encoded_sequence = []
    count = 1

    for i in range(1, len(sequence)):
        if sequence[i] == sequence[i - 1]:
            count += 1
        else:
            encoded_sequence.append(count)
            count = 1

    encoded_sequence.append(count)
    if sequence[0] != 1:
        encoded_sequence.insert(0, 0)

    return encoded_sequence

def count_occurrences(lst, n):
    count = 0
    for num in lst:
        if num == n:
            count += 1
    return count

# Set the source directory containing the CSV files
source_directory = "."

# Set the output file path for the combined CSV file
output_file_path = "all-ds-with-run-length.csv"

# Call the function to combine the CSV files
combine_csv_files(source_directory, output_file_path)

# add one more column to change difsets to sequences in binary, and extract run-length
new_header = []
rows_with_new_column = []
with open(output_file_path, 'r') as csvfile:
    reader = csv.reader(csvfile)
    header = next(reader)
    new_header.extend(header)
    new_header.append("ds-sequence")
    new_header.append("run-length")
    new_header.append("run-length size")
    new_header.append("number of 1")
    new_header.append("is-prime")
    new_header.append("is-composite")
    new_header.append("is-cyclic-group")
    new_header.append("is-hadmard-ds")
    new_header.append("is-singer-ds")

    for row in reader:
        if len(row)==0:
            continue
        order = int(row[0])
        idx = int(row[1])
        k = int(row[3])
        lambd = int(row[6])
        cyclic_groups = get_all_cyclic_groups("cyclic-groups.csv")

        ds = ast.literal_eval(row[-1])
        sequence = convert_to_sequence(ds, int(row[0]))
        run_length = run_length_encoding(sequence)
        new_row = row
        new_row.append(sequence)
        new_row.append(run_length)
        new_row.append(len(run_length))
        new_row.append(count_occurrences(run_length, 1))

        isPrime = bool(is_prime(order))
        new_row.append(isPrime)  # 是否为素数
        new_row.append(not isPrime)  # 是否为合数
        
        is_cyclic = True if (order, idx) in cyclic_groups else False
        new_row.append(is_cyclic)  # 是否为循环群

        b_is_hadamard = is_hadamard(order, k, lambd)
        new_row.append(b_is_hadamard)  # 是否为Hadmard差集

        b_is_singer = is_singer(order, k, lambd)
        new_row.append(b_is_singer)  # 是否为Singer差集
        
        rows_with_new_column.append(new_row)

with open(output_file_path,'w',newline='') as file:
    writer = csv.writer(file)
    writer.writerow(new_header)
    writer.writerows(rows_with_new_column)